package pers.xiaojun.boot.module.system.service.tenant;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import pers.xiaojun.boot.common.enums.CommonStatusEnum;
import pers.xiaojun.boot.common.exception.BusinessException;
import pers.xiaojun.boot.module.system.controller.permission.vo.permission.AssignRoleMenuReqVO;
import pers.xiaojun.boot.module.system.controller.permission.vo.permission.AssignUserRoleReqVO;
import pers.xiaojun.boot.module.system.controller.permission.vo.role.RoleSaveVO;
import pers.xiaojun.boot.module.system.controller.tenant.vo.tenant.TenantQueryReqVO;
import pers.xiaojun.boot.module.system.controller.tenant.vo.tenant.TenantSaveReqVO;
import pers.xiaojun.boot.module.system.controller.user.vo.user.UserSaveReqVO;
import pers.xiaojun.boot.module.system.dao.entity.permission.RoleDO;
import pers.xiaojun.boot.module.system.dao.entity.tenant.TenantDO;
import pers.xiaojun.boot.module.system.dao.entity.tenant.TenantPackageDO;
import pers.xiaojun.boot.module.system.dao.entity.user.AdminUserDO;
import pers.xiaojun.boot.module.system.dao.mapper.tenant.TenantMapper;
import pers.xiaojun.boot.module.system.enums.permission.RoleCodeEnum;
import pers.xiaojun.boot.module.system.service.permission.PermissionService;
import pers.xiaojun.boot.module.system.service.permission.RoleService;
import pers.xiaojun.boot.module.system.service.user.UserService;
import pers.xiaojun.boot.mybatis.core.convert.PageConvert;
import pers.xiaojun.boot.mybatis.core.query.LambdaQueryWrapperX;
import pers.xiaojun.boot.tenant.core.util.TenantUtils;

import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Objects;

import static pers.xiaojun.boot.module.system.constants.BusinessCodeConstants.*;

/**
 * 租户服务实现类
 *
 * @author xiaojun
 * @since 2025-11-22
 */
@Service
@RequiredArgsConstructor
public class TenantServiceImpl extends ServiceImpl<TenantMapper, TenantDO> implements TenantService {

    private final TenantPackageService tenantPackageService;
    private final UserService userService;
    private final RoleService roleService;
    private final PermissionService permissionService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TenantDO saveTenant(TenantSaveReqVO saveVO) {
        // 校验基础信息
        validateTenantBasicInfo(null, saveVO.getName(), saveVO.getWebsite());
        // 校验租户套餐是否可用
        TenantPackageDO tenantPackage = tenantPackageService.validateTenantPackageAvailable(saveVO.getPackageId());

        TenantDO tenant = BeanUtil.toBean(saveVO, TenantDO.class);
        this.baseMapper.insert(tenant);

        TenantUtils.execute(tenant.getId(), () -> {
            RoleDO role = createRole(tenantPackage);
            AdminUserDO user = createUser(role.getId(), saveVO);
            // 更新租户联系人Id
            this.baseMapper.updateById(new TenantDO().setId(tenant.getId()).setContactUserId(user.getId()));
        });

        return tenant;
    }

    @Override
    public TenantDO updateTenant(TenantSaveReqVO updateVO) {
        return null;
    }

    @Override
    public void removeTenantById(Long tenantId) {
        validateTenantExists(tenantId);
        this.baseMapper.deleteById(tenantId);
    }

    @Override
    public void removeTenantByIds(Collection<Long> tenantIds) {

    }

    @Override
    public TenantDO getTenantById(Long tenantId) {
        return validateTenantExists(tenantId);
    }

    @Override
    public TenantDO getTenantByName(String tenantName) {
        TenantDO tenant = this.baseMapper.selectByName(tenantName);
        if (tenant == null) {
            throw new BusinessException(TENANT_NOT_EXISTS);
        }
        return tenant;
    }

    @Override
    public Page<TenantDO> listTenantsPage(TenantQueryReqVO queryVO) {
        return this.baseMapper.selectPage(PageConvert.INSTANCE.toPage(queryVO), new LambdaQueryWrapperX<TenantDO>()
                .likeIfPresent(TenantDO::getName, queryVO.getName())
                .likeIfPresent(TenantDO::getContactName, queryVO.getContactName())
                .likeIfPresent(TenantDO::getContactMobile, queryVO.getContactMobile())
                .eqIfPresent(TenantDO::getStatus, queryVO.getStatus())
                .betweenIfPresent(TenantDO::getCreateTime, queryVO.getCreateTime())
        );
    }

    @Override
    public void validTenantAvailable(Long tenantId) {
        TenantDO tenant = validateTenantExists(tenantId);
        // 是否禁用
        if (CommonStatusEnum.isDisable(tenant.getStatus())) {
            throw new BusinessException(TENANT_DISABLED);
        }
        // 是否过期
        if (tenant.getExpireTime().isBefore(LocalDateTime.now())) {
            throw new BusinessException(TENANT_EXPIRED);
        }
    }

    /**
     * 创建角色
     *
     * @param tenantPackage 租户套餐信息
     * @return 角色信息
     */
    private RoleDO createRole(TenantPackageDO tenantPackage) {
        // 创建租户角色
        RoleDO role = roleService.saveRole(new RoleSaveVO()
                .setName(RoleCodeEnum.TENANT_ADMIN.getName())
                .setCode(RoleCodeEnum.TENANT_ADMIN.getCode())
                .setSort(0)
                .setStatus(CommonStatusEnum.ENABLE.getStatus())
                .setRemark("系统自动生成")
        );
        // 分配菜单
        permissionService.assignRoleMenu(new AssignRoleMenuReqVO()
                .setRoleId(role.getId())
                .setMenuIds(tenantPackage.getMenuIds())
        );
        return role;
    }

    /**
     * 创建用户
     *
     * @param roleId 角色Id
     * @param saveVO 保存的租户信息
     * @return 用户信息
     */
    private AdminUserDO createUser(Long roleId, TenantSaveReqVO saveVO) {
        // 创建用户
        AdminUserDO user = userService.saveUser(BeanUtil.toBean(saveVO, UserSaveReqVO.class)
                .setNickname(saveVO.getContactName())
        );
        // 分配角色
        permissionService.assignUserRole(new AssignUserRoleReqVO()
                .setUserId(user.getId())
                .setRoleIds(Sets.newHashSet(roleId))
        );
        return user;
    }

    /**
     * 校验租户基础信息
     *
     * @param tenantId 租户套餐Id
     * @param name     租户名称
     * @param website  租户域名
     */
    public void validateTenantBasicInfo(Long tenantId, String name, String website) {
        TenantDO tenant;
        if (name != null) {
            tenant = this.baseMapper.selectByName(name);
            if (tenant != null && !Objects.equals(tenant.getId(), tenantId)) {
                throw new BusinessException(TENANT_NAME_EXISTS);
            }
        }
        if (website != null) {
            tenant = this.baseMapper.selectByWebsite(website);
            if (tenant != null && !Objects.equals(tenant.getId(), tenantId)) {
                throw new BusinessException(TENANT_WEBSITE_EXISTS);
            }
        }
    }

    /**
     * 校验租户是否存在
     *
     * @param tenantId 租户套餐Id
     * @return 租户信息
     */
    private TenantDO validateTenantExists(Long tenantId) {
        TenantDO tenant = this.baseMapper.selectById(tenantId);
        if (tenant == null) {
            throw new BusinessException(TENANT_NOT_EXISTS);
        }
        return tenant;
    }

}
